#include "MaterialViewWidget.h"
#include <SEngine/Render/BaseRenderer.h>
#include <SEEdit/Render/RenderFeature/DebugRenderFeature.h>
#include <SEEdit/Render/RenderPass/TestRenderPass.h>
#include <SEEdit/Render/RenderPass/GizmoRenderPass.h>
#include <SEEdit/Render/RenderPass/GridRenderPass.h>
#include <SEngine/Render/RenderPass/SkyboxRenderPass.h>
#include <SEEdit/Render/RenderPass/MaterialViewRenderPass.h>
#include <SERender/Descriptors/FrameDescriptor.h>
#include <SECore/Events/Input.h>
#include <glm/glm.hpp>
#include <SEUi/SEUi.h>
#include <SEngine/Ecs/Components/HDRSkyboxComp.h>
#include <SEngine/Ecs/Components/LightComp.h>
#include <SEngine/Ecs/Components/TransformComp.h>
#include <SEngine/Ecs/Components/UuidComp.h>
#include <SEngine/Ecs/Components/ModelRenderComp.h>
#include <SEngine/Ecs/Components/NameComp.h>
#include <SEngine/Render/Descriptors/SceneDescriptor.h>
#include <SECore/Manager.h>
#include <SEDebug/Log/Log.h>

#include <SERender/Resourses/Loader/TextureLoader.h>
#include <SEngine/Render/Entity/MeshFilter.h>


namespace SEngine
{

    MaterialViewWidget::MaterialViewWidget(EditLayer & layer)
        : Widget(), m_layer(layer)
    {
        m_scene = std::make_shared<Scene>();

        TextureLoader<Texture2D> texLoader;
        texLoader.SetInternalFormat(RGB);
        texLoader.SetFormat(RGB);
        texLoader.SetType(UNSIGNED_BYTE);
        texLoader.SetParameter(TEXTURE_MAG_FILTER, LINEAR);
        texLoader.SetParameter(TEXTURE_MIN_FILTER, LINEAR);
        texLoader.SetParameter(TEXTURE_WRAP_S, CLAMP_TO_EDGE);
        texLoader.SetParameter(TEXTURE_WRAP_T, CLAMP_TO_EDGE);
        m_targetMap = texLoader.CreateTexture(800, 600, nullptr);
        m_fbo = std::make_unique<FrameBuffer>();
        m_fbo->SwapAttachments(Attachment::COLOR_ATTACHMENT0, *m_targetMap);

        
        m_renderer = std::make_unique<BaseRenderer>(std::make_unique<CurrentDrive>());
        
        m_renderer->Descriptor<RenderPass>::AddDescriptor(std::make_unique<SkyboxRenderPass>(*m_renderer));
        m_renderer->Descriptor<RenderFeature>::AddDescriptor(std::make_unique<DebugRenderFeature>(*m_renderer));
        m_renderer->Descriptor<RenderPass>::AddDescriptor(std::make_unique<TestRenderPass>(*m_renderer));
        m_renderer->Descriptor<RenderPass>::AddDescriptor(std::make_unique<MaterialViewRenderPass>(*m_renderer));
        m_renderer->Descriptor<RenderPass>::AddDescriptor(std::make_unique<GridRenderPass>(*m_renderer));
     
        m_renderer->SetFrameBuffer(*m_fbo);

        // Add Light
        auto & lightActor = m_scene->CreateActor();
        lightActor.AddComponent<TransformComp>().translate = glm::vec3{-20.0f, 20.0f, -20.0f};
        lightActor.AddComponent<PointLightComp>().light.SetEnergy(3000.0f);
        m_pointLight = lightActor.weak_from_this();

        auto & dirlightActor = m_scene->CreateActor();
        dirlightActor.AddComponent<TransformComp>().rotate = glm::radians(glm::vec3{0.0f, 45.0f, -45.0f});
        dirlightActor.AddComponent<DirectLightComp>().light.SetEnergy(1.0f);
        m_directLight = dirlightActor.weak_from_this();

        // Add Base Actor
        auto & baseActor = m_scene->CreateActor();
        baseActor.AddComponent<UuidComp>();
        baseActor.AddComponent<NameComp>();
        baseActor.AddComponent<TransformComp>().scale = glm::vec3{5.0f};
        baseActor.AddComponent<ModelRenderComp>().m_model.SetMeshFilter(Manager::GetInstance().Get<MeshFilter>("Sphere").value(), Manager::GetInstance().Get<Material>("Standard").value());
        m_baseActor = baseActor.shared_from_this();

        auto & skyboxActor = m_scene->CreateActor();
        skyboxActor.AddComponent<UuidComp>();
        skyboxActor.AddComponent<NameComp>();
        skyboxActor.AddComponent<TransformComp>();
        skyboxActor.AddComponent<HDRSkyboxComp>();
        m_hdrSkybox = skyboxActor.weak_from_this(); 

        m_renderer->AnyDescriptor::AddDescriptor<SceneDescriptor>(std::move(SceneDescriptor{m_scene}));
        m_renderer->AnyDescriptor::AddDescriptor<MaterialDescriptor>(std::move(MaterialDescriptor{Manager::GetInstance().Get<Material>("Standard").value()}));
    
        this->SetWindowFlag(ImGuiWindowFlags_MenuBar, true);
    }

    void MaterialViewWidget::LoadMaterial(ResRef<Material> material)
    {
        auto & materialDes = m_renderer->AnyDescriptor::GetDescriptor<MaterialDescriptor>()->get();
        materialDes.material = material;
    }

    void MaterialViewWidget::BeginUpdate()
    {
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f});
    }

    void MaterialViewWidget::UpdateImpl(int delta)
    {
        ShowMenuBar();
        m_scene->OnUpdate(delta);
        auto rect = this->GetRect();
        rect.w -= 40;        // 减去titel高度
        m_renderer->AnyDescriptor::AddDescriptor<FrameDescriptor>(FrameDescriptor{0, 0, rect.z, rect.w, m_editCamera});
        m_renderer->BeginFrame();
        m_renderer->DrawFrame();
        m_renderer->EndFrame();
        ImGui::Image((ImTextureID)(m_targetMap->GetId()), {(float)rect.z, (float)rect.w}, {0.0f, 1.0f}, {1.0f, 0.0f});
    }

    void MaterialViewWidget::EndUpdate()
    {
        ImGui::PopStyleVar();
    }

    void MaterialViewWidget::ShowMenuBar()
    {
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {9.0f, 9.0f});
        if (ImGui::BeginMenuBar()) {
            if (ImGui::BeginMenu("Camera")) {
                auto & skybox = m_hdrSkybox.lock()->GetComponent<HDRSkyboxComp>()->get().skybox;
                if (ImGui::BeginCombo("Skybox", !skybox ? "None" : skybox.Name().c_str())) {
                    if (ImGui::Selectable("None")) {
                        skybox.Reset();
                    }
                    Manager::GetInstance().Foreach<TextureHDR>([&](ResRef<TextureHDR> & res) {
                        if (ImGui::Selectable(res.Name().c_str())) {
                            skybox = Manager::GetInstance().Get<TextureHDR>(res.Name()).value();
                        }
                    });
                    ImGui::EndCombo();
                }
                ImGui::ColorEdit3("Clear Color", &m_editCamera.GetClearColor().x);
                ImGui::DragFloat("zNear", &m_editCamera.GetZNear(), 0.01f, 0.01f, m_editCamera.GetZFar());
                ImGui::DragFloat("zFar", &m_editCamera.GetZFar(), 0.01f, m_editCamera.GetZNear(), 1000.0f);
                ImGui::EndMenu();
            }
            if (ImGui::BeginMenu("Point Light")) {
                auto & trans = m_pointLight.lock()->GetComponent<TransformComp>()->get();
                auto & light = m_pointLight.lock()->GetComponent<PointLightComp>()->get().light;
                float energy = light.GetEnergy();
                glm::vec3 color = light.GetColor();
                ImGui::DragFloat3("Translate", &trans.translate.x, 0.01f);
                ImGui::DragFloat("Intensity", &energy, 0.01f);
                ImGui::ColorEdit3("Color", &color.x);
                light.SetColor(color);
                light.SetEnergy(energy);
                ImGui::EndMenu();
            }
            if (ImGui::BeginMenu("Direct Light")) {
                auto & trans = m_directLight.lock()->GetComponent<TransformComp>()->get();
                auto & light = m_directLight.lock()->GetComponent<DirectLightComp>()->get().light;
                glm::vec3 eulerAngles = glm::eulerAngles(trans.rotate);
                eulerAngles = glm::degrees(eulerAngles);
                ImGui::DragFloat3("Rotate", &eulerAngles.x, 0.1f);
                trans.rotate = glm::radians(eulerAngles);
                float energy = light.GetEnergy();
                glm::vec3 color = light.GetColor();
                ImGui::DragFloat("Intensity", &energy, 0.01f);
                ImGui::ColorEdit3("Color", &color.x);
                light.SetColor(color);
                light.SetEnergy(energy);
                ImGui::EndMenu();
            }
            ImGui::EndMenuBar();
        }
        ImGui::PopStyleVar();
    }


} // namespace SEngine
